// -----------------------------
// Author: 		Dhaenens Gert	
// Creation: 	8/4/2013 12:40:22 PM				
// -----------------------------

#include "LuaScript.h"
#include "Lua.h"
#include "LuaError.h"
#include "LuaStackGuard.h"
#include "LuaTable.h"

#include <string.h>

namespace ObjectLua
{

	LuaScript::LuaScript(Lua* lpLua, const char* filePath)
		: LuaObject(lpLua)
		, m_FilePath(nullptr)
		, m_PathLength(0)
		, m_bIsLoaded(false)
		, m_Ref(lpLua)
	{
		m_PathLength = strnlen_s(filePath,512) + 1;
		m_FilePath = new char[m_PathLength];
		strcpy_s(m_FilePath,m_PathLength,filePath);
	}	
	LuaScript::LuaScript(const LuaScript& refLuaScript)
		: LuaObject(refLuaScript.m_lpLua)
		, m_FilePath(nullptr)
		, m_PathLength(refLuaScript.m_PathLength)
		, m_bIsLoaded(refLuaScript.m_bIsLoaded)
		, m_Ref(refLuaScript.m_Ref)
	{
		m_FilePath = new char[m_PathLength];
		strcpy_s(m_FilePath,m_PathLength,refLuaScript.m_FilePath);
	}
	LuaScript& LuaScript::operator=(const LuaScript& refLuaScript)
	{
		m_lpLua = refLuaScript.m_lpLua;
		m_PathLength = refLuaScript.m_PathLength;
		m_bIsLoaded = refLuaScript.m_bIsLoaded;
		m_Ref = refLuaScript.m_Ref;
		
		m_FilePath = new char[m_PathLength];
		strcpy_s(m_FilePath,m_PathLength,refLuaScript.m_FilePath);

		return (*this);
	}
	LuaScript::~LuaScript()
	{
		delete[] m_FilePath;
		if(m_bIsLoaded)
			unload();
	}

	void LuaScript::load()
	{
		LUA_ASSERT(m_lpLua);
		LUA_ASSERT(m_PathLength > 0);

		// Get the Object from the Stack
		lua_State* lpState = m_lpLua->getState();
		// If it isn't loaded yet
		// Load it into memory first
		if(!m_bIsLoaded)
		{
			// Load the File
			m_lpLua->getStack()->loadFile(m_FilePath);

			// Create the Environment
			m_lpLua->getStack()->requestTable();
			m_lpLua->getStack()->requestMetaTable(m_FilePath);
			m_lpLua->getStack()->pushString("__index");
			m_lpLua->getStack()->getGlobal("_G");
			m_lpLua->getStack()->setTable(-3);
			m_lpLua->getStack()->setMetaTable(-2);

			// Set the Environment
			m_lpLua->getStack()->setupvalue(-2, 1);
			// Get the Stack Ref
			m_Ref.obtainRef();
			// Set the loaded flag
			m_bIsLoaded = true;
		}
	}
	void LuaScript::reload()
	{
		unload();
		m_bIsLoaded = false;
		load();
	}

	void LuaScript::unload()
	{
		if(m_bIsLoaded)
		{
			m_Ref.pop();
			m_bIsLoaded = false;
		}
	}

	void LuaScript::run()
	{
		LuaStackGuard stackGuard(m_lpLua);
		
		m_Ref.push();

		// Call the Script
		m_lpLua->getStack()->pcall(0, -1);
	}

	LuaVariable LuaScript::getVariable(const char* Name)
	{
		LuaStackGuard LuaStackGuard(m_lpLua);
		m_Ref.push();
		m_lpLua->getStack()->getupvalue(-1, 1);
		
		m_lpLua->getStack()->getField(-1, Name);

		LuaRef ref = LuaRef(m_lpLua);
		ref.obtainRef();

		return LuaVariable(m_lpLua, this, Name, ref);
	}

	void LuaScript::callFunction(const char* name)
	{
		LuaStackGuard stackGuard(m_lpLua);
		m_Ref.push();
		m_lpLua->getStack()->getupvalue(-1, 1);


		// Get the Function
		m_lpLua->getStack()->getField(-1, name);

		// Call the Function
		m_lpLua->getStack()->pcall(0,0);
	}

}